Skip to content

Conversation

@kinyoklion
Copy link
Member

@kinyoklion kinyoklion commented Aug 17, 2022

This PR adds top level tests for the LDClientImpl as well as LDClientNode.

Some tests have a certain amount of duplication between the two to ensure that the platform level tests are covered.

The tests are largely ports of the tests from the node SDK.

…r levels, but we need to check the event emitter.
@shortcut-integration
Copy link

This pull request has been linked to Shortcut Story #162616: Implement LDClient unit tests..

@kinyoklion kinyoklion changed the title Rlamb/sc 162616/implement ldclient tests #3 Implement additional LDClient tests. Aug 17, 2022
"ts-jest": "^27.1.4",
"typescript": "^4.6.3"
"typescript": "^4.6.3",
"launchdarkly-js-test-helpers": "^2.2.0"
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The node level tests can benefit from this helper. For now I have excluded it from common, and server-common, because those tests should execute outside node without many polyfills or dependencies if we need them to. We may be able to more widely use them later.

@@ -0,0 +1,151 @@
import { integrations, interfaces, LDBigSegmentsOptions, LDLogger } from '@launchdarkly/js-server-sdk-common';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are some node level big segments test for the event emitter implementation. The main testing is done in the common sdk.

@@ -0,0 +1,164 @@
import { integrations } from '@launchdarkly/js-server-sdk-common';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Most of the file data source testing is at the common level, but here we make sure it works with the actual node filesystem APIs.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's just the I/O implementation that's distinctive here, I feel like you might be able to make the tests a bit simpler by omitting things like the segment. I mean, the fact that there's a flag referencing a segment is a detail of the data that's in the file, which should be orthogonal to how we read the file or detected changes to the file.

@@ -0,0 +1,93 @@
import { integrations } from '@launchdarkly/js-server-sdk-common';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Primarily for the event emitter connection.

@@ -1,5 +1,5 @@
import * as os from 'os';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to follow directory structure.

@@ -1,6 +1,6 @@
import * as http from 'http';
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to follow directory structure.

@kinyoklion kinyoklion marked this pull request as ready for review August 17, 2022 21:46
Copy link
Contributor

@eli-darkly eli-darkly left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good - I left a couple of comments about optional changes to consider.

@@ -0,0 +1,164 @@
import { integrations } from '@launchdarkly/js-server-sdk-common';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's just the I/O implementation that's distinctive here, I feel like you might be able to make the tests a bit simpler by omitting things like the segment. I mean, the fact that there's a flag referencing a segment is a detail of the data that's in the file, which should be orthogonal to how we read the file or detected changes to the file.

() => { },
() => { },
// Always listen to events.
() => true,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something that's occurred to me during this reviews in general is that the large number of LDClientImpl constructor parameters makes it a bit hard to see which one is which. Might you consider creating a type whose only purpose is to make some of these into named properties? Like, the first three parameters are mandatory and generally self-explanatory at the call site, but these other callbacks not so much. If the usage were something like this—

    new LDClientImpl(
      sdkKey,
      platform,
      config,
      {
        hasEventListeners: () => true
      });

—it'd be easier to see what's happening, and possibly harder to make a mistake by putting parameters in the wrong order. In this example I've assumed that there is some default behavior for the unspecified ones, which might not make sense in a non-test context since (I think) all of the SDK implementations are likely to need to provide all of those callbacks, but even if they're all mandatory & therefore can't make the test code less verbose, I feel like there might be some benefit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've implemented this change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does remove some verbosity in tests, because I added a makeCallbacks(withEvents:boolean) helper that most tests can use.

targets: [],
rules: [
{
clauses: [{ attribute: 'key', op: 'in', values: [defaultUser.key] }],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a thought for future test writing: something I've done in other SDKs, and wish I had gotten around to in Node, is to rely more heavily on helper functions for generating boilerplate pieces of flag configuration like this. For instance, if the idea is to make a clause that will definitely match this user, I would change this to something like clauses: [clauseThatMatchesUser(defaultUser)] and define clauseThatMatchesUser to be equivalent to this. Even though this kind of logic isn't rocket science and isn't incredibly verbose, I find that it's easier for me to understand and validate the test logic at a glance when there are fewer extraneous details and I can see the intention immediately from the names of things, rather than having to infer it from my knowledge of how such a clause would be evaluated.

Base automatically changed from rlamb/fixes-from-testing to main August 23, 2022 16:28
@kinyoklion kinyoklion merged commit 1f2bba7 into main Aug 23, 2022
@kinyoklion kinyoklion deleted the rlamb/sc-162616/implement-ldclient-tests branch August 23, 2022 17:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants